#pragma once
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;


namespace zch {

    template<class T>
    class auto_ptr  //管理权转移
    {
    public:
        auto_ptr(T* ptr = nullptr)
            :_ptr(ptr)
        {}

        auto_ptr(auto_ptr<T>& ap)
            :_ptr(ap._ptr)
        {
            ap._ptr = nullptr;
        }

        auto_ptr<T>& operator=(auto_ptr<T>& ap)
        {
            if (this != &ap)
            {
                delete _ptr;
                _ptr = ap._ptr;
                ap._ptr = nullptr;
            }

            return *this;
        }

        T& operator*()
        {
            return *_ptr;
        }

        T* operator->()
        {
            return _ptr;
        }

        ~auto_ptr()
        {
            if (_ptr != nullptr)
            {
                delete _ptr;
                _ptr = nullptr;
            }
        }
    private:
        T* _ptr;
    };

    template<class T>
    class unique_ptr  //防拷贝
    {
    public:
        unique_ptr(T* ptr = nullptr)
            :_ptr(ptr)
        {}

        ~unique_ptr()
        {
            if (_ptr != nullptr)
            {
                delete _ptr;
                _ptr = nullptr;
            }
        }

        T& operator*()
        {
            return *_ptr;
        }

        T* operator->()
        {
            return _ptr;
        }
    private:
        unique_ptr<T>& operator=(unique_ptr<T>&) = delete;
        unique_ptr(unique_ptr<T>&) = delete;
    private:
        T* _ptr;
    };

    template<class T>
    class shared_ptr   //引用计数
    {
    private:
        void addRef()
        {
            //_pmtx->lock();
            ++(*_count);
            //_pmtx->unlock();
        }

        void releaseRef()
        {
            //_pmtx->lock();
            bool flag = false;
            if (--(*_count) == 0)
            {
                if (_ptr != nullptr)
                {
                    delete _ptr;
                    _ptr = nullptr;
                }
                delete _count;
                _count = nullptr;
                flag = true;
            }
            //_pmtx->unlock();

            if (flag == true)
            {
                delete _pmtx;
                _pmtx = nullptr;
            }
        }

    public:
        shared_ptr(T* ptr = nullptr)
            :_ptr(ptr)
            ,_count(new int(1))
            ,_pmtx(new mutex)
        {}

        shared_ptr(shared_ptr<T>& sp)
            :_ptr(sp._ptr)
            , _count(sp._count)
            ,_pmtx(sp._pmtx)
        {
            addRef(); //计数
        }

        shared_ptr operator=(shared_ptr<T>& sp)
        {
            if (_ptr != sp._ptr)
            {
                releaseRef();
                _ptr = sp._ptr;
                _count = sp._count;
                _pmtx = sp._pmtx;
                addRef();
            }

            return *this;
        }

        ~shared_ptr()
        {
            releaseRef();

        }
        int use_count()
        {
            return *_count;
        }
        T& operator*()
        {
            return *_ptr;
        }

        T* operator->()
        {
            return _ptr;
        }
    private:
        T* _ptr;
        mutex* _pmtx;
        int* _count;
    };
}